/**
 * @file    drv_can.c
 * @author  yhy
 * @brief   芯必达IM94x系列芯片, can抽象层
 * @version 1.03
 * @date    2025-07-07
 *
 * @copyright Copyright (c) 2025
 *
 * @details
 * Change Logs:
 * Date           Author       Notes
 * 2025-07-07     yhy          the first version V1.00
 * 2025-07-11     yhy          所有函数和变量名修改为snf_开头 V1.01
 * 2025-07-16     yhy          修复了snf_drv_can_convert_errcode函数传入ERR_SUCCESS返回ERROR的BUG V1.02
 * 2025-07-17     yhy          修复了CAN发送数据时会将数据长度设置为固定 8Byte or 64Byte的BUG V1.03
 *
 */
#include "drv_can.h"

#include "can_drv.h"
#include "can_reg_access.h"
#include "gpio_drv.h"

#include <string.h>

/**
 * @brief CAN引脚路由
 *
 */
typedef struct
{
    GPIO_Type     *tx_port; /*!< CAN TX引脚端口 */
    uint32_t       tx_pin;  /*!< CAN TX引脚编号 */
    GPIO_Type     *rx_port; /*!< CAN RX引脚端口 */
    uint32_t       rx_pin;  /*!< CAN RX引脚编号 */
    gpio_pin_mux_t mux;     /*!< CAN 引脚复用 */
} snf_can_pin_route_t;

/**
 * @brief CAN硬件实例管理
 *
 */
typedef struct
{
    bool           initialized;       /*!< CAN实例是否初始化 */
    bool           fd_enable;         /*!< CAN是否使能CAN-FD */
    can_callback_f tx_callback;       /*!< CAN-Tx回调函数 */
    void          *tx_callback_param; /*!< CAN-Tx回调函数参数 */
    can_callback_f rx_callback;       /*!< CAN-Rx回调函数 */
    void          *rx_callback_param; /*!< CAN-Rx回调函数参数 */
    can_state_t    state;             /*!< CAN状态 */
    CAN_Type      *canX_addr;         /*!< CAN实例地址 */
} snf_can_hw_manager_t;

static void      snf_drv_can_config(const snf_can_config_t *can_init_config);
static void      snf_drv_can_callback(uint32_t hw_instance, can_event_t event, void *param);
static void      snf_drv_can_gpio_init(const snf_can_config_t *can_init_config);
static uint32_t  snf_drv_can_get_hw_instance(snf_can_instance_e can_instance);
static CAN_Type *snf_drv_can_get_hw_instance_addr(uint32_t hw_instance);
static result_e  snf_drv_can_validate_instance(snf_can_instance_e instance);
static result_e  snf_drv_can_convert_errcode(errcode_t errcode);

static can_config_t can_base_config = {
    .mode = CAN_NORMAL_MODE,              
    .srcClk = CAN_CLK_SRC_APB,                          
    .busOffAutoRec = true,                
    .warnValue = 3,     
    /* 500Kbps */                 
    .bitrate = {                         
        .prescaler = 1U,                 
        .phaseSeg1 = 49U,                 
        .phaseSeg2 = 8U,                  
        .rJumpwidth = 4U,                
    },
    /* 2Mbps */
    .bitrateFd = {                       
        .prescaler = 1U,                 
        .phaseSeg1 = 11U,                  
        .phaseSeg2 = 1U,                 
        .rJumpwidth = 1U,                
    },
};

/* CAN std frame config */
static can_data_info_t can_std_msg_config = {
    .BRS        = 0,
    .dataLength = 8,
    .FDF        = 0,
    .IDE        = 0,
    .RTR        = 0,
};

/* CAN fd frame config */
static can_data_info_t can_fd_msg_config = {
    .BRS        = 1,  /* 使能更高比特率 */
    .dataLength = 64, /* CAN FD支持的数据长度 */
    .FDF        = 1,  /* CAN FD */
    .IDE        = 0,
    .RTR        = 0,
};

/* CAN filter table, mask bit 0: must fit, 1: at will */
static can_filter_config_t can_filter_table[CAN_FILTER_MAXSIZE];

/* CAN引脚配置表 */
static const snf_can_pin_route_t can_pin_route_table[CAN_INSTANCE_MAXSIZE] = {
    [CAN_INSTANCE_CAN0_0] = { GPIOE, 5, GPIOE, 4, GPIO_PIN_MUX_FUN5 },
    [CAN_INSTANCE_CAN0_1] = { GPIOC, 3, GPIOC, 2, GPIO_PIN_MUX_FUN3 },
    [CAN_INSTANCE_CAN0_2] = { GPIOB, 1, GPIOB, 0, GPIO_PIN_MUX_FUN5 },
    [CAN_INSTANCE_CAN0_3] = { GPIOA, 3, GPIOA, 2, GPIO_PIN_MUX_FUN4 },
    [CAN_INSTANCE_CAN1_0] = { GPIOA, 6, GPIOE, 7, GPIO_PIN_MUX_FUN4 },
    [CAN_INSTANCE_CAN1_1] = { GPIOC, 7, GPIOC, 6, GPIO_PIN_MUX_FUN4 },
    [CAN_INSTANCE_CAN1_2] = { GPIOA, 13, GPIOA, 12, GPIO_PIN_MUX_FUN4 },
    [CAN_INSTANCE_CAN2_0] = { GPIOC, 17, GPIOC, 16, GPIO_PIN_MUX_FUN5 },
    [CAN_INSTANCE_CAN2_1] = { GPIOB, 13, GPIOB, 12, GPIO_PIN_MUX_FUN5 },
};

/* CAN实例管理器集合 - 每个硬件CAN实例一个管理器 */
static snf_can_hw_manager_t can_hw_manager_list[CAN_HW_INSTANCE_MAXSIZE] = { 0 };

static const IRQn_Type can_irq_table[CAN_HW_INSTANCE_MAXSIZE] = { CAN0_IRQn, CAN1_IRQn, CAN2_IRQn };
static const uint8_t   CAN_IRQ_PRIORITY                       = 1;

/**
 * @brief  CAN初始化
 *
 * @param   can_init_config     CAN配置结构体指针
 * @return  result_e            初始化结果, 初始化成功返回RESULT_STATUS_OK, 否则返回错误码
 */
result_e snf_drv_can_init(const snf_can_config_t *can_init_config)
{
    /* 参数检查 */
    if (can_init_config == NULL) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    result_e result = snf_drv_can_validate_instance(can_init_config->instance);
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    /* 获取硬件实例编号 */
    uint32_t hw_instance = snf_drv_can_get_hw_instance(can_init_config->instance);
    if (hw_instance >= CAN_HW_INSTANCE_MAXSIZE) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    /* 保存用户回调函数和参数 */
    can_hw_manager_list[hw_instance].tx_callback       = can_init_config->tx_callback;
    can_hw_manager_list[hw_instance].tx_callback_param = can_init_config->tx_callback_param;
    can_hw_manager_list[hw_instance].rx_callback       = can_init_config->rx_callback;
    can_hw_manager_list[hw_instance].rx_callback_param = can_init_config->rx_callback_param;
    can_hw_manager_list[hw_instance].fd_enable         = can_init_config->fd_enable;
    can_hw_manager_list[hw_instance].canX_addr         = snf_drv_can_get_hw_instance_addr(hw_instance);

    /* 配置CAN模块 */
    snf_drv_can_config(can_init_config);

    /* GPIO初始化 */
    snf_drv_can_gpio_init(can_init_config);

    /* CAN基础配置初始化 */
    errcode_t ret = CAN_Init(hw_instance, &can_hw_manager_list[hw_instance].state, &can_base_config);
    if (ret != ERR_SUCCESS) {
        return snf_drv_can_convert_errcode(ret);
    }

    /* CAN过滤器配置初始化 */
    CAN_SetRxFilter(hw_instance, CAN_FILTER_MAXSIZE, &can_filter_table[0]);

    /* 注册回调函数 */
    CAN_InstallCallback(hw_instance, snf_drv_can_callback, NULL);

    /* 设置CAN中断优先级 */
    NVIC_SetPriority(can_irq_table[hw_instance], CAN_IRQ_PRIORITY);

    can_hw_manager_list[hw_instance].initialized = true;
    return RESULT_STATUS_OK;
}

/**
 * @brief CAN反初始化
 *
 * @param instance      CAN实例
 * @return result_e     反初始化结果, 反初始化成功返回RESULT_STATUS_OK, 否则返回错误码
 */
result_e snf_drv_can_deinit(snf_can_instance_e instance)
{
    result_e result = snf_drv_can_validate_instance(instance);
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    uint32_t hw_instance = snf_drv_can_get_hw_instance(instance);
    if (!can_hw_manager_list[hw_instance].initialized) {
        return RESULT_STATUS_CAN_NOT_INITIALIZED;
    }

    CAN_Deinit(hw_instance);
    memset(&can_hw_manager_list[hw_instance], 0, sizeof(snf_can_hw_manager_t));

    return RESULT_STATUS_OK;
}

/**
 * @brief 发送一帧CAN数据到总线上
 *
 * @param   instance        CAN实例
 * @param   frame           CAN帧
 * @return  result_e        发送结果, 发送成功返回RESULT_STATUS_OK, 否则返回错误码
 */
result_e snf_drv_can_transmit(snf_can_instance_e instance, const snf_can_frame_t *frame)
{
    if (frame == NULL) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    /* 校验CAN实例 */
    result_e result = snf_drv_can_validate_instance(instance);
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    /* 获取硬件实例, 并判断是否初始化 */
    uint32_t hw_instance = snf_drv_can_get_hw_instance(instance);
    if (!can_hw_manager_list[hw_instance].initialized) {
        return RESULT_STATUS_CAN_NOT_INITIALIZED;
    }

    /* 校验数据长度 */
    if (frame->dlc > (can_hw_manager_list[hw_instance].fd_enable ? 64 : 8)) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    /* 根据是否是CAN_FD模式, 获取数据信息 */
    can_data_info_t *msg_config;
    if (can_hw_manager_list[hw_instance].fd_enable) {
        can_fd_msg_config.dataLength = frame->dlc;
        msg_config                   = &can_fd_msg_config;
    }
    else {
        can_std_msg_config.dataLength = frame->dlc;
        msg_config                    = &can_std_msg_config;
    }

    errcode_t ret =
        CAN_Send(hw_instance, CAN_SECONDARY_TRANSMIT_BUFFER, msg_config, frame->std_id, frame->data);

    return snf_drv_can_convert_errcode(ret);
}

/**
 * @brief 配置CAN模块
 *
 * @param can_init_config CAN初始化配置结构体指针
 */
static void snf_drv_can_config(const snf_can_config_t *can_init_config)
{
    /* 配置CAN模块 */
    can_base_config.fdEnable = can_init_config->fd_enable;

    /* 配置CAN过滤器 */
    for (uint8_t i = 0; i < CAN_FILTER_MAXSIZE; ++i) {
        can_filter_table[i].code = can_init_config->filter[i].code;
        can_filter_table[i].mask = can_init_config->filter[i].mask;
    }
}

/**
 * @brief 初始化CAN引脚
 *
 * @param can_init_config   CAN初始化配置结构体
 */
static void snf_drv_can_gpio_init(const snf_can_config_t *can_init_config)
{
    /* 配置CAN引脚 */
    const snf_can_pin_route_t *can_pin_config = &can_pin_route_table[can_init_config->instance];

    /* Tx 引脚 */
    GPIO_SetPinFunc(can_pin_config->tx_port, can_pin_config->tx_pin, can_pin_config->mux);
    /* Rx 引脚 */
    GPIO_SetPinFunc(can_pin_config->rx_port, can_pin_config->rx_pin, can_pin_config->mux);
}

/**
 * @brief  根据snf_can_instance_e获取CAN实例
 *
 * @param can_instance  can实例
 * @return uint32_t     CAN HW num
 */
static uint32_t snf_drv_can_get_hw_instance(snf_can_instance_e can_instance)
{
    static uint32_t instance_table[] = {
        [CAN_INSTANCE_CAN0_0] = 0, [CAN_INSTANCE_CAN0_1] = 0, [CAN_INSTANCE_CAN0_2] = 0,
        [CAN_INSTANCE_CAN0_3] = 0, [CAN_INSTANCE_CAN1_0] = 1, [CAN_INSTANCE_CAN1_1] = 1,
        [CAN_INSTANCE_CAN1_2] = 1, [CAN_INSTANCE_CAN2_0] = 2, [CAN_INSTANCE_CAN2_1] = 2,
    };

    return instance_table[(uint32_t)can_instance];
}

/**
 * @brief 获取硬件CAN实例地址
 *
 * @param hw_instance   CAN HW num
 * @return CAN_Type*    CAN实例地址
 */
static CAN_Type *snf_drv_can_get_hw_instance_addr(uint32_t hw_instance)
{
    static CAN_Type *can_hw_instance_table[] = { CAN0, CAN1, CAN2 };

    return can_hw_instance_table[hw_instance];
}

/**
 * @brief 验证CAN实例有效性
 *
 * @param instance      CAN实例
 * @return result_e     验证结果, 验证成功返回RESULT_STATUS_OK, 否则返回错误码
 */
static result_e snf_drv_can_validate_instance(snf_can_instance_e instance)
{
    if (instance >= CAN_INSTANCE_MAXSIZE) {
        return RESULT_STATUS_INVALID_PARAM;
    }
    return RESULT_STATUS_OK;
}

/**
 * @brief 转换底层错误码
 *
 * @param errcode   底层错误码
 * @return result_e CAN错误码
 */
static result_e snf_drv_can_convert_errcode(errcode_t errcode)
{
    switch (errcode) {
    case ERR_SUCCESS: return RESULT_STATUS_OK;
    case ERR_BUSY:    return RESULT_STATUS_CAN_BUSY;
    case ERR_TIMEOUT: return RESULT_STATUS_CAN_TIMEOUT;
    default:          return RESULT_STATUS_CAN_ERROR;
    }
}

/**
 * @brief  CAN回调函数
 *
 * @param instance  CAN实例
 * @param event     CAN事件
 * @param param     CAN回调函数参数
 */
static void snf_drv_can_callback(uint32_t hw_instance, can_event_t event, void *param)
{
    if (hw_instance >= CAN_HW_INSTANCE_MAXSIZE) {
        return;
    }

    snf_can_hw_manager_t *can_manager = &can_hw_manager_list[hw_instance];
    if (!can_manager->initialized) {
        return;
    }

    switch (event) {
    case CAN_EVENT_RX_COMPLETE:
        if (can_manager->rx_callback != NULL) {
            can_msgbuff_t frame;
            errcode_t     ret = CAN_Receive(hw_instance, &frame);
            if (ERR_SUCCESS == ret) {
                snf_can_frame_t can_frame;
                can_frame.std_id = frame.msgId;
                can_frame.dlc    = frame.dataLen;
                memcpy(can_frame.data, frame.data, can_frame.dlc);
                can_manager->rx_callback(hw_instance, &can_frame);
            }
            else {}
        }
        else {}

        break;
    case CAN_EVENT_STB_TX_COMPLETE:
    case CAN_EVENT_PTB_TX_COMPLETE:
        if (can_manager->tx_callback != NULL) {
            can_manager->tx_callback(hw_instance, can_manager->tx_callback_param);
        }
        break;
    default: break;
    }
}
